package org.jivesoftware.smack.util;

import java.io.PrintStream;
import java.util.AbstractCollection;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.jivesoftware.smack.util.collections.AbstractMapEntry;

public class Cache<K, V>
  implements Map<K, V>
{
  protected LinkedList ageList;
  protected long cacheHits;
  protected long cacheMisses = 0L;
  protected LinkedList lastAccessedList;
  protected Map<K, CacheObject<V>> map;
  protected int maxCacheSize;
  protected long maxLifetime;

  public Cache(int paramInt, long paramLong)
  {
    if (paramInt == 0)
      throw new IllegalArgumentException("Max cache size cannot be 0.");
    this.maxCacheSize = paramInt;
    this.maxLifetime = paramLong;
    this.map = new HashMap(103);
    this.lastAccessedList = new LinkedList();
    this.ageList = new LinkedList();
  }

  /**
   * @deprecated
   */
  public void clear()
  {
    int j;
    monitorenter;
    try
    {
      Object[] arrayOfObject = this.map.keySet().toArray();
      int i = arrayOfObject.length;
      j = 0;
      if (j >= i)
      {
        this.map.clear();
        this.lastAccessedList.clear();
        this.ageList.clear();
        this.cacheHits = 0L;
        this.cacheMisses = 0L;
        monitorexit;
        return;
      }
      remove(arrayOfObject[j]);
    }
    finally
    {
      monitorexit;
    }
  }

  /**
   * @deprecated
   */
  public boolean containsKey(Object paramObject)
  {
    monitorenter;
    try
    {
      deleteExpiredEntries();
      boolean bool = this.map.containsKey(paramObject);
      monitorexit;
      return bool;
    }
    finally
    {
      localObject = finally;
      monitorexit;
      throw localObject;
    }
  }

  /**
   * @deprecated
   */
  public boolean containsValue(Object paramObject)
  {
    monitorenter;
    try
    {
      deleteExpiredEntries();
      CacheObject localCacheObject = new CacheObject(paramObject);
      boolean bool = this.map.containsValue(localCacheObject);
      monitorexit;
      return bool;
    }
    finally
    {
      localObject = finally;
      monitorexit;
      throw localObject;
    }
  }

  /**
   * @deprecated
   */
  protected void cullCache()
  {
    int k;
    monitorenter;
    try
    {
      int j;
      int i = this.maxCacheSize;
      if (i < 0);
      do
      {
        do
        {
          monitorexit;
          return;
        }
        while (this.map.size() <= this.maxCacheSize);
        deleteExpiredEntries();
        j = (int)(0.90000000000000002D * this.maxCacheSize);
        k = this.map.size();
      }
      while (k <= j);
      if (remove(this.lastAccessedList.getLast().object, true) == null)
      {
        System.err.println("Error attempting to cullCache with remove(" + this.lastAccessedList.getLast().object.toString() + ") - " + "cacheObject not found in cache!");
        this.lastAccessedList.getLast().remove();
      }
    }
    finally
    {
      monitorexit;
    }
  }

  /**
   * @deprecated
   */
  protected void deleteExpiredEntries()
  {
    Object localObject2;
    monitorenter;
    try
    {
      long l2;
      long l1 = this.maxLifetime;
      if (l1 <= 0L);
      do
      {
        do
        {
          monitorexit;
          return;
          localObject2 = this.ageList.getLast();
        }
        while (localObject2 == null);
        l2 = System.currentTimeMillis() - this.maxLifetime;
      }
      while (l2 <= ((LinkedListNode)localObject2).timestamp);
      if (remove(((LinkedListNode)localObject2).object, true) == null)
      {
        System.err.println("Error attempting to remove(" + ((LinkedListNode)localObject2).object.toString() + ") - cacheObject not found in cache!");
        ((LinkedListNode)localObject2).remove();
      }
      LinkedListNode localLinkedListNode = this.ageList.getLast();
      localObject2 = localLinkedListNode;
    }
    finally
    {
      monitorexit;
    }
  }

  /**
   * @deprecated
   */
  public Set<Map.Entry<K, V>> entrySet()
  {
    monitorenter;
    try
    {
      deleteExpiredEntries();
      2 local2 = new AbstractSet(this)
      {
        private final Set<Map.Entry<K, Cache.CacheObject<V>>> set;

        public Iterator<Map.Entry<K, V>> iterator()
        {
          return new Iterator(this)
          {
            private final Iterator<Map.Entry<K, Cache.CacheObject<V>>> it;

            public boolean hasNext()
            {
              return this.it.hasNext();
            }

            public Map.Entry<K, V> next()
            {
              Map.Entry localEntry = (Map.Entry)this.it.next();
              return new AbstractMapEntry(this, localEntry.getKey(), ((Cache.CacheObject)localEntry.getValue()).object)
              {
                public V setValue()
                {
                  throw new UnsupportedOperationException("Cannot set");
                }
              };
            }

            public void remove()
            {
              this.it.remove();
            }
          };
        }

        public int size()
        {
          return this.set.size();
        }
      };
      monitorexit;
      return local2;
    }
    finally
    {
      localObject = finally;
      monitorexit;
      throw localObject;
    }
  }

  /**
   * @deprecated
   */
  public V get(Object paramObject)
  {
    CacheObject localCacheObject;
    Object localObject2;
    monitorenter;
    try
    {
      deleteExpiredEntries();
      localCacheObject = (CacheObject)this.map.get(paramObject);
      if (localCacheObject == null)
      {
        this.cacheMisses = (1L + this.cacheMisses);
        localObject2 = null;
        monitorexit;
        return localObject2;
      }
      localCacheObject.lastAccessedListNode.remove();
      this.lastAccessedList.addFirst(localCacheObject.lastAccessedListNode);
      this.cacheHits = (1L + this.cacheHits);
      localCacheObject.readCount = (1 + localCacheObject.readCount);
    }
    finally
    {
      monitorexit;
    }
  }

  public long getCacheHits()
  {
    return this.cacheHits;
  }

  public long getCacheMisses()
  {
    return this.cacheMisses;
  }

  public int getMaxCacheSize()
  {
    return this.maxCacheSize;
  }

  public long getMaxLifetime()
  {
    return this.maxLifetime;
  }

  /**
   * @deprecated
   */
  public boolean isEmpty()
  {
    monitorenter;
    try
    {
      deleteExpiredEntries();
      boolean bool = this.map.isEmpty();
      monitorexit;
      return bool;
    }
    finally
    {
      localObject = finally;
      monitorexit;
      throw localObject;
    }
  }

  /**
   * @deprecated
   */
  public Set<K> keySet()
  {
    monitorenter;
    try
    {
      deleteExpiredEntries();
      Set localSet = Collections.unmodifiableSet(this.map.keySet());
      monitorexit;
      return localSet;
    }
    finally
    {
      localObject = finally;
      monitorexit;
      throw localObject;
    }
  }

  /**
   * @deprecated
   */
  public V put(K paramK, V paramV)
  {
    monitorenter;
    Object localObject1 = null;
    try
    {
      if (this.map.containsKey(paramK))
        localObject1 = remove(paramK, true);
      CacheObject localCacheObject = new CacheObject(paramV);
      this.map.put(paramK, localCacheObject);
      localCacheObject.lastAccessedListNode = this.lastAccessedList.addFirst(paramK);
      LinkedListNode localLinkedListNode = this.ageList.addFirst(paramK);
      localLinkedListNode.timestamp = System.currentTimeMillis();
      localCacheObject.ageListNode = localLinkedListNode;
      cullCache();
      monitorexit;
      return localObject1;
    }
    finally
    {
      localObject2 = finally;
      monitorexit;
      throw localObject2;
    }
  }

  public void putAll(Map<? extends K, ? extends V> paramMap)
  {
    Iterator localIterator = paramMap.entrySet().iterator();
    while (true)
    {
      if (!(localIterator.hasNext()))
        return;
      Map.Entry localEntry = (Map.Entry)localIterator.next();
      Object localObject = localEntry.getValue();
      if (localObject instanceof CacheObject)
        localObject = ((CacheObject)localObject).object;
      put(localEntry.getKey(), localObject);
    }
  }

  /**
   * @deprecated
   */
  public V remove(Object paramObject)
  {
    monitorenter;
    try
    {
      Object localObject2 = remove(paramObject, false);
      monitorexit;
      return localObject2;
    }
    finally
    {
      localObject1 = finally;
      monitorexit;
      throw localObject1;
    }
  }

  /**
   * @deprecated
   */
  public V remove(Object paramObject, boolean paramBoolean)
  {
    CacheObject localCacheObject;
    Object localObject2;
    monitorenter;
    try
    {
      localCacheObject = (CacheObject)this.map.remove(paramObject);
      if (localCacheObject == null)
      {
        localObject2 = null;
        monitorexit;
        return localObject2;
      }
      localCacheObject.lastAccessedListNode.remove();
      localCacheObject.ageListNode.remove();
      localCacheObject.ageListNode = null;
      localCacheObject.lastAccessedListNode = null;
    }
    finally
    {
      monitorexit;
    }
  }

  /**
   * @deprecated
   */
  public void setMaxCacheSize(int paramInt)
  {
    monitorenter;
    try
    {
      this.maxCacheSize = paramInt;
      cullCache();
      monitorexit;
      return;
    }
    finally
    {
      localObject = finally;
      monitorexit;
      throw localObject;
    }
  }

  public void setMaxLifetime(long paramLong)
  {
    this.maxLifetime = paramLong;
  }

  /**
   * @deprecated
   */
  public int size()
  {
    monitorenter;
    try
    {
      deleteExpiredEntries();
      int i = this.map.size();
      monitorexit;
      return i;
    }
    finally
    {
      localObject = finally;
      monitorexit;
      throw localObject;
    }
  }

  /**
   * @deprecated
   */
  public Collection<V> values()
  {
    monitorenter;
    try
    {
      deleteExpiredEntries();
      Collection localCollection = Collections.unmodifiableCollection(new AbstractCollection(this)
      {
        Collection<Cache.CacheObject<V>> values;

        public Iterator<V> iterator()
        {
          return new Iterator(this)
          {
            Iterator<Cache.CacheObject<V>> it;

            public boolean hasNext()
            {
              return this.it.hasNext();
            }

            public V next()
            {
              return ((Cache.CacheObject)this.it.next()).object;
            }

            public void remove()
            {
              this.it.remove();
            }
          };
        }

        public int size()
        {
          return this.values.size();
        }
      });
      monitorexit;
      return localCollection;
    }
    finally
    {
      localObject = finally;
      monitorexit;
      throw localObject;
    }
  }

  private static class CacheObject<V>
  {
    public Cache.LinkedListNode ageListNode;
    public Cache.LinkedListNode lastAccessedListNode;
    public V object;
    public int readCount = 0;

    public CacheObject(V paramV)
    {
      this.object = paramV;
    }

    public boolean equals(Object paramObject)
    {
      boolean bool;
      if (this == paramObject)
        bool = true;
      while (true)
      {
        while (true)
        {
          return bool;
          if (paramObject instanceof CacheObject)
            break;
          bool = false;
        }
        CacheObject localCacheObject = (CacheObject)paramObject;
        bool = this.object.equals(localCacheObject.object);
      }
    }

    public int hashCode()
    {
      return this.object.hashCode();
    }
  }

  private static class LinkedList
  {
    private Cache.LinkedListNode head = new Cache.LinkedListNode("head", null, null);

    public LinkedList()
    {
      Cache.LinkedListNode localLinkedListNode1 = this.head;
      Cache.LinkedListNode localLinkedListNode2 = this.head;
      Cache.LinkedListNode localLinkedListNode3 = this.head;
      localLinkedListNode2.previous = localLinkedListNode3;
      localLinkedListNode1.next = localLinkedListNode3;
    }

    public Cache.LinkedListNode addFirst(Object paramObject)
    {
      Cache.LinkedListNode localLinkedListNode = new Cache.LinkedListNode(paramObject, this.head.next, this.head);
      localLinkedListNode.previous.next = localLinkedListNode;
      localLinkedListNode.next.previous = localLinkedListNode;
      return localLinkedListNode;
    }

    public Cache.LinkedListNode addFirst(Cache.LinkedListNode paramLinkedListNode)
    {
      paramLinkedListNode.next = this.head.next;
      paramLinkedListNode.previous = this.head;
      paramLinkedListNode.previous.next = paramLinkedListNode;
      paramLinkedListNode.next.previous = paramLinkedListNode;
      return paramLinkedListNode;
    }

    public Cache.LinkedListNode addLast(Object paramObject)
    {
      Cache.LinkedListNode localLinkedListNode = new Cache.LinkedListNode(paramObject, this.head, this.head.previous);
      localLinkedListNode.previous.next = localLinkedListNode;
      localLinkedListNode.next.previous = localLinkedListNode;
      return localLinkedListNode;
    }

    public void clear()
    {
      Cache.LinkedListNode localLinkedListNode1 = getLast();
      while (true)
      {
        if (localLinkedListNode1 == null)
        {
          Cache.LinkedListNode localLinkedListNode2 = this.head;
          Cache.LinkedListNode localLinkedListNode3 = this.head;
          Cache.LinkedListNode localLinkedListNode4 = this.head;
          localLinkedListNode3.previous = localLinkedListNode4;
          localLinkedListNode2.next = localLinkedListNode4;
          return;
        }
        localLinkedListNode1.remove();
        localLinkedListNode1 = getLast();
      }
    }

    public Cache.LinkedListNode getFirst()
    {
      Cache.LinkedListNode localLinkedListNode2;
      Cache.LinkedListNode localLinkedListNode1 = this.head.next;
      if (localLinkedListNode1 == this.head)
        localLinkedListNode2 = null;
      while (true)
      {
        return localLinkedListNode2;
        localLinkedListNode2 = localLinkedListNode1;
      }
    }

    public Cache.LinkedListNode getLast()
    {
      Cache.LinkedListNode localLinkedListNode2;
      Cache.LinkedListNode localLinkedListNode1 = this.head.previous;
      if (localLinkedListNode1 == this.head)
        localLinkedListNode2 = null;
      while (true)
      {
        return localLinkedListNode2;
        localLinkedListNode2 = localLinkedListNode1;
      }
    }

    public String toString()
    {
      Cache.LinkedListNode localLinkedListNode = this.head.next;
      StringBuilder localStringBuilder = new StringBuilder();
      while (true)
      {
        if (localLinkedListNode == this.head)
          return localStringBuilder.toString();
        localStringBuilder.append(localLinkedListNode.toString()).append(", ");
        localLinkedListNode = localLinkedListNode.next;
      }
    }
  }

  private static class LinkedListNode
  {
    public LinkedListNode next;
    public Object object;
    public LinkedListNode previous;
    public long timestamp;

    public LinkedListNode(Object paramObject, LinkedListNode paramLinkedListNode1, LinkedListNode paramLinkedListNode2)
    {
      this.object = paramObject;
      this.next = paramLinkedListNode1;
      this.previous = paramLinkedListNode2;
    }

    public void remove()
    {
      this.previous.next = this.next;
      this.next.previous = this.previous;
    }

    public String toString()
    {
      return this.object.toString();
    }
  }
}